/*
Copyright (C) 2008  Helmut Juskewycz
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.juskewycz.dividere.action.join;

import com.juskewycz.dividere.action.IProgressListener;
import com.juskewycz.dividere.action.IProgressObserverable;
import com.juskewycz.dividere.action.ProgressStatus;
import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Implements some default behavior of a joiner like adding/removing listeners
 * and some error handling. This class also adds <code>IProgressObserverable</code>
 * as an interface. This allows to observe the progress of the process.
 * 
 * @author Helmut Juskewycz
 * @createdon 27. January 2008
 * @lastmodified 27. January 2008
 * @history
 * 27. January 2008 Finished version 1.0
 */
public abstract class AJoiner implements IJoiner, IProgressObserverable {

    private Logger logger = Logger.getLogger(AJoiner.class.getName());
    protected static final Comparator fileComparator = new Comparator() {

	public int compare(Object a, Object b) {
	    File filea = (File) a;
	    File fileb = (File) b;

	    return filea.getName().compareTo(fileb.getName());
	}
    };
    protected static final int ONE_MB = 1048576;
    protected static final int BUFF_SIZE = (ONE_MB * 4);
    protected static final byte[] buffer = new byte[BUFF_SIZE];
    protected final List<IJoinListener> joinListeners = new ArrayList<IJoinListener>(1);
    protected final List<IProgressListener> progressListeners = new ArrayList<IProgressListener>(1);

    protected void notifyFileJoinBegin(final File joinedFile) {
	for (IJoinListener iJoinListener : joinListeners) {
	    iJoinListener.fileJoinBegin(joinedFile);
	}
    }

    protected void notifyFileJoined(final File joinedFile) {
	for (IJoinListener iJoinListener : joinListeners) {
	    iJoinListener.fileJoined(joinedFile);
	}
    }

    protected void notifyPartProcessBegin(final File part) {
	for (IJoinListener iJoinListener : joinListeners) {
	    iJoinListener.partProcessBegin(part);
	}
    }

    protected void notifyPartProcessed(final File part) {
	for (IJoinListener iJoinListener : joinListeners) {
	    iJoinListener.partProcessed(part);
	}
    }

    protected void notifyProgressListeners(ProgressStatus status) {
	for (IProgressListener iProgressListener : progressListeners) {
	    iProgressListener.update(status);
	}
    }

    protected void notifyError(ProgressStatus status) {
	for (IProgressListener iProgressListener : progressListeners) {
	    iProgressListener.error(status);
	}
    }

    protected boolean checkAllPartFilesAvailable(File[] files) {
	int index = 1;
	for (File file : files) {
	    try {
		String partNumber = file.getPath().substring(file.getPath().lastIndexOf(".") + 1);
		if (index != Integer.parseInt(partNumber)) {
		    return false;
		}
		index++;
	    } catch (Exception ex) {
		if (logger.isLoggable(Level.INFO)) {
		    logger.log(Level.INFO, null, ex);
		}
		return false;
	    }
	}
	return true;
    }

    protected String getOriginalFilePath(String numberedPath) {
	int index = numberedPath.lastIndexOf(".");
	if (index < 0) {
	    notifyError(new ProgressStatus(0, 0, ERROR_PATH_MISSING_DOT, true));
	    logger.log(Level.SEVERE, ERROR_PATH_MISSING_DOT);
	    return null;
	}
	return numberedPath.substring(0, index);
    }

    protected boolean checkOutputFile(File file) {
	if (file.exists()) {
	    notifyError(new ProgressStatus(0, 0, ERROR_OUTPUT_FILE_EXISTS, true));
	    return false;
	}
	return true;
    }

    public void addListener(final IJoinListener listener) {
	joinListeners.add(listener);
    }

    public void removeListener(final IJoinListener listener) {
	joinListeners.remove(listener);
    }

    public void addListener(final IProgressListener listener) {
	progressListeners.add(listener);
    }

    public void removeListener(final IProgressListener listener) {
	progressListeners.remove(listener);
    }
}
